from flask import Flask, jsonify, request
from sensors import raspi, temperature, led
from datetime import datetime
import requests
import config
import util
import json
from util import HttpException
from sensors.models import Sensor

app = Flask(__name__)


def auth(data, headers):
    if not util.validate_token(data, headers.get('x-token')):
        raise HttpException('token error', 401)


@app.errorhandler(HttpException)
def handle_http_exception(e):
    response = jsonify(e.response())
    response.status_code = e.status
    return response


@app.after_request
def add_header(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response


@app.route('/sensors', methods=['POST'])
def sensor_create():
    util.mongo_connect()

    data = request.get_json()
    auth(data, request.headers)
    Sensor(**data).save(validate=False)

    return jsonify(data)


@app.route('/sensors', methods=['GET'])
def device_index():
    util.mongo_connect()

    args = request.args.to_dict()
    if 'grain' not in args or 'device_name' not in args:
        raise HttpException('need "grain" and "device_name" param', 422)

    documents = Sensor.objects(device_name=args['device_name'], grain=args['grain']).order_by('-created_at')

    # 分页
    limit = int(args.get('limit', 10))
    documents = documents.limit(limit)
    if 'skip' in args:
        documents = documents.skip(args['skip'])

    # 查询字段限制
    if 'fields' in args:
        query_fields = {}
        for field in args['fields'].split(','):
            query_fields.update({field: True})
        documents = documents.fields(**query_fields)

    # 原始查询数据
    data = []
    for item in documents:
        row = json.loads(item.to_json())
        data.append(row)

    # serials 操作
    # serials 使用 url_query:...&serials=a,b
    # 数据[{"a":"aa","b":"bb"}] 返回[{"a":"aa","b":"bb","s":"a","s_val":"aa"},{"a":"aa","b":"bb","s":"b","s_val":"bb"}]
    # 既原数据不变，需要serial处理的数据单独添加并数量加倍
    if 'serials' in args:
        serials = args['serials'].split(',')
        data = util.data_serial(data, serials)

    # map 操作
    # map 使用 url_query:...&maps=a->x,b->y 则返回字段中a替换为x b替换为y
    if 'maps' in args:
        maps = []
        for item in args['maps'].split(','):
            maps.append(item.split('->'))
        data = util.data_map(data, maps)

    return jsonify(data)


@app.cli.command()
def monitor():
    util.gpio_connect()
    light = led.Led(17)

    data = {'created_at': str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')), 'grain': config.monitor_grain}
    data.update(raspi.get_data())
    data.update(temperature.get_data())

    headers = {'x-token': util.generate_token(data)}
    try:
        response = requests.post(config.web_deploy_url + '/sensors', json=data, headers=headers, timeout=5)

        if response.status_code == 200:
            light.flicker()
            print(200)
        elif response.status_code == 401:
            light.flicker(2)
            print(401)
        else:
            light.flicker(3)
            print('monitor error')

    except Exception:
        light.flicker(5)
        print('connect error')

    util.gpio_close()


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
